
/*
 * Hlpay-Plus aggregate payment system. Copyright
 * (c) 2022-2023 Hlpay Team Copyright has the right of final interpretation.
 */
package com.hlkj.pay.controller.admin;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.pojo.PageResult;
import com.hlkj.framework.common.util.collection.CollectionUtils;
import com.hlkj.pay.app.adminuser.IOrganizationAppService;
import com.hlkj.pay.app.transfer.OrganizationDoToResp;
import com.hlkj.pay.controller.BaseController;
import com.hlkj.pay.dto.admin.OrganizationQueryDto;
import com.hlkj.pay.enums.AdminUserEnum;
import com.hlkj.pay.infrastructure.model.admin.OrganizationDO;
import com.hlkj.pay.service.admin.IOrganizationService;
import com.hlkj.pay.vo.admin.req.organization.OrganizationPageReq;
import com.hlkj.pay.vo.admin.req.organization.OrganizationReq;
import com.hlkj.pay.vo.admin.resp.organization.OrganizationResp;
import com.hlkj.pay.vo.common.req.DeleteCodeReq;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.StringUtil;

/**
 * @author HlpayTeam
 * @date 2024/09/08 11:14
 */
@Tag(name = "组织配置")
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/v1/adminuser/organization")
public class AdminOrganizationController extends BaseController  {

    private final IOrganizationService organizationService;
    private final IOrganizationAppService organizationAppService;
    @Operation(summary  = "组织列表page")
    @GetMapping("/page")
    public CommonResult<OrganizationResp> queryOrganizationPage(OrganizationPageReq organizationPageReq) {
        OrganizationQueryDto organizationQueryDto = new OrganizationQueryDto();
        organizationQueryDto.setSysType(organizationPageReq.getSysType());
        organizationQueryDto.setType(AdminUserEnum.ORGANIZATION_TYPE.HEAD_OFFICE.getCode());
        organizationQueryDto.setPageNo(organizationPageReq.getPageNo());
        organizationQueryDto.setPageSize(organizationPageReq.getPageSize());
        organizationQueryDto.setLikeOrganizationName(organizationPageReq.getName());
        organizationQueryDto.setSn(organizationPageReq.getSn());
        PageResult<OrganizationDO> organizationPage = organizationService.queryOrganizationPage(organizationQueryDto);
        List<OrganizationDO> organizationList = organizationPage.getList();
        if (CollectionUtils.isEmpty(organizationList)) {
            return buildPageResult(organizationPage,Collections.emptyList());
        }
        List<OrganizationDO> organizations=new ArrayList<>(200);
        List<String> organizationCodes = organizationList.stream()
                .map(organizationDO -> organizationDO.getOrganizationCode()).collect(Collectors.toList());
        organizationCodes.stream().forEach(organizationCode->{
            OrganizationQueryDto organizationQuery = new OrganizationQueryDto();
            organizationQuery.setSysType(organizationPageReq.getSysType());
            organizationQuery.setLikeOrganizationCode(organizationCode);
            List<OrganizationDO> childOrganizationList = organizationService.queryOrganizationList(organizationQuery);
            organizations.addAll(childOrganizationList);
        });
        List<OrganizationResp> organizationResps = OrganizationDoToResp.INSTANCE.doToRespList(organizations);
        processMerchantList(organizationResps);
        List<OrganizationResp> resps = buildOrganizationTree(organizationResps);
        return buildPageResult(organizationPage,resps);
    }
    @Operation(summary  = "组织列表")
    @GetMapping("")
    public CommonResult<List<OrganizationResp>> queryOrganization(OrganizationPageReq organizationPageReq) {
        OrganizationQueryDto organizationQueryDto = new OrganizationQueryDto();
        organizationQueryDto.setSysType(organizationPageReq.getSysType());
        organizationQueryDto.setType(AdminUserEnum.ORGANIZATION_TYPE.HEAD_OFFICE.getCode());
        List<OrganizationDO> organizationList = organizationService.queryOrganizationList(organizationQueryDto);
        List<OrganizationDO> organizations=new ArrayList<>(200);
        if (CollectionUtils.isEmpty(organizationList)) {
            return CommonResult.success(Collections.emptyList());
        }
        List<String> organizationCodes = organizationList.stream()
                .map(organizationDO -> organizationDO.getOrganizationCode()).collect(Collectors.toList());
        organizationCodes.stream().forEach(organizationCode->{
            OrganizationQueryDto organizationQuery = new OrganizationQueryDto();
            organizationQuery.setSysType(organizationPageReq.getSysType());
            organizationQuery.setLikeOrganizationCode(organizationCode);
           
            List<OrganizationDO> childOrganizationList = organizationService.queryOrganizationList(organizationQuery);
            organizations.addAll(childOrganizationList);
        });
        List<OrganizationResp> organizationResps = OrganizationDoToResp.INSTANCE.doToRespList(organizations);
        processMerchantList(organizationResps);
        List<OrganizationResp> resps = buildOrganizationTree(organizationResps);
        return CommonResult.success(resps);
    }
    
    
    @Operation(summary  = "组织详情")
    @GetMapping("/detail")
    public CommonResult<OrganizationResp> queryOrganizationDetail(@RequestParam("organizationCode") String organizationCode) {
        OrganizationDO organizationDO = organizationService.queryOrganizationDetail(organizationCode);
        if (organizationDO == null) {
            return CommonResult.success();
        }
        OrganizationResp organizationResp = OrganizationDoToResp.INSTANCE.domainToResp(organizationDO);
        return CommonResult.success(organizationResp);
    }
    
    @Operation(summary  = "新增组织")
    @PostMapping("")
    public CommonResult<Void> addOrganization(@Validated @RequestBody OrganizationReq organizationReq) {
        return organizationAppService.addOrganization(organizationReq);
    }
    
    @Operation(summary  = "更新组织")
    @PutMapping("")
    public CommonResult<Void> updateOrganization(@Validated @RequestBody OrganizationReq organizationReq) {
        return organizationAppService.updateOrganization(organizationReq);
    }
    @Operation(summary  = "更新组织")
    @DeleteMapping("")
    public CommonResult<Void> delOrganization(@Validated @RequestBody DeleteCodeReq deleteCodeReq) {
        return organizationAppService.delOrganization(deleteCodeReq.getCode());
    }
    
    
    // Recursive method to build the tree
    public static List<OrganizationResp> buildOrganizationTree(List<OrganizationResp> organizationList) {
        // Map to store organizationCode -> OrganizationResp mapping for quick access
        // Map<String, OrganizationResp> organizationMap = organizationList.stream()
        //         .collect(Collectors.toMap(OrganizationResp::getOrganizationCode, org -> org));
        Map<String, List<OrganizationResp>> organizationMap = organizationList.stream().filter(organizationResp -> StringUtil.hasText(organizationResp.getParentOrganizationCode()))
                .collect(Collectors.groupingBy(OrganizationResp::getParentOrganizationCode));
        
        List<OrganizationResp> rootOrganizations = new ArrayList<>();
        
        for (OrganizationResp organization : organizationList) {
            if (organization.getParentOrganizationCode() == null || organization.getParentOrganizationCode().isEmpty()) {
                // If no parentOrganizationCode, it's a root organization
                rootOrganizations.add(organization);
                // organization.setChildOrganizations(organizationMap.get(organization.getOrganizationCode()));
            } else {
                // Get the parent organization from the map
                // OrganizationResp parentOrganization = organizationMap.get(organization.getParentOrganizationCode());
                // if (parentOrganization != null) {
                //     // Add the current organization to the parent's child organizations
                //     parentOrganization.getChildOrganizations().add(organization);
                // }
            }
            organization.setChildOrganizations(organizationMap.get(organization.getOrganizationCode()));
        }
        
        return rootOrganizations; // Return the list of root organizations
    }
}
